package com.sencorsta.ids.core.tcp.opensocket.client;

import com.sencorsta.ids.core.log.Out;
import com.sencorsta.ids.core.tcp.opensocket.OpenDecoder;
import com.sencorsta.ids.core.tcp.opensocket.OpenEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.ThreadPerTaskExecutor;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;


public class OpenClientBootstrap {

    // 存放NIO客户端实例对象
    public static Map<String, Channel> clientMap = new ConcurrentHashMap<String, Channel>();

    private String serverIp;
    private int serverPort;
    private Bootstrap bootstrap;
    //private EventLoopGroup group;
    private ChannelFuture channelFuture;

    private static final EventLoopGroup m_loop =new NioEventLoopGroup(0,new ThreadPerTaskExecutor(new DefaultThreadFactory("OpenClient")));


    public OpenClientBootstrap() {
        //group = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.option(ChannelOption.TCP_NODELAY, true);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();

                //注意，这个专门针对 Socket 信息的解码器只能放在 SocketChooseHandler 之后，否则会导致 webSocket 连接出错
                pipeline.addLast("decoder", new OpenDecoder());
                pipeline.addLast("encoder", new OpenEncoder());

                pipeline.addLast("commonhandler", new OpenClientChannelHandler());
            }
        });
        bootstrap.group(m_loop);




        Runtime.getRuntime().addShutdownHook(new Thread(()->{
            for (String s:clientMap.keySet()) {
                try {
                    this.close(s);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }));
    }



    public Channel connect(String id,String host, int port) {
        try {
            ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
            future.awaitUninterruptibly(3, TimeUnit.SECONDS);
            if (!future.isSuccess()) {
                if (future.cause() != null) {
                    Out.trace("连接服务器出错:", future.cause().getMessage());
                }
                return null;
            }
            Channel channel=future.channel();
            OpenClientBootstrap.clientMap.put(id,channel);
            return channel;
        } catch (Exception e) {
            Out.error("连接服务器出错", "host:", host, " port:", port + " -> " + e.getMessage());
            return null;
        }
    }

    public void write(Object obj) {
        if (!channelFuture.channel().isOpen() || !channelFuture.channel().isWritable() || obj == null) {
            return;
        }
        channelFuture.channel().writeAndFlush(obj);
    }

    public void close(String id) throws InterruptedException {
        Out.trace("开始关闭链接：" + id);
        //group.shutdownGracefully();
        Channel channel = clientMap.get(id);
        if (channel != null) {
            //channel.closeFuture().sync();
            channel.close();
            clientMap.remove(id);
            Out.trace("关闭链接成功：" + id);
        } else {
            Out.trace("没有此链接：" + id);
        }
    }



}
